/* 
 * File:   Scanner.cpp
 * Author: michele
 * 
 * Created on February 15, 2012, 2:01 PM
 */
#include "Scanner.h"

//#include <cstring>

using namespace std;
/* The source file */


/*int read_ch(void) {
  int ch = fgetc(source);
  cur_col++;
  if (ch == '\n') {
    cur_line++;
    cur_col = 0;
  }
  return ch;
}
 
void put_back(int ch) {
  ungetc(ch, source);
  cur_col--;
  if (ch == '\n') cur_line--;
}
 */

void Scanner::init_keywords(){
    //std::basic_string<char> a();
    Keyws.insert(pair<string,Keywords>("integer",INTEGER));
    Keyws.insert(pair<string,Keywords>("boolean",BOOLEAN));
    Keyws.insert(pair<string,Keywords>("<",LT));
    Keyws.insert(pair<string,Keywords>(">",GT));
    Keyws.insert(pair<string,Keywords>("<=",LE));
    Keyws.insert(pair<string,Keywords>(">=", GE));
    Keyws.insert(pair<string,Keywords>("==", EQ));
    Keyws.insert(pair<string,Keywords>("<>", NE));
    Keyws.insert(pair<string,Keywords>("and", AND));
    Keyws.insert(pair<string,Keywords>("or", OR));
    Keyws.insert(pair<string,Keywords>("not", NOT));
    Keyws.insert(pair<string,Keywords>("write", WRITE));
    Keyws.insert(pair<string,Keywords>("read", READ));
    Keyws.insert(pair<string,Keywords>("while", WHILE));
    Keyws.insert(pair<string,Keywords>("do", DO));
    Keyws.insert(pair<string,Keywords>("if", IF));
    Keyws.insert(pair<string,Keywords>("then", THEN));
    Keyws.insert(pair<string,Keywords>("else", ELSE));
    Keyws.insert(pair<string,Keywords>("var", VAR));
    Keyws.insert(pair<string,Keywords>("program", PRG_INIT));
    Keyws.insert(pair<string,Keywords>("begin", BLK_INIT));
    Keyws.insert(pair<string,Keywords>("end", BLK_END));
    Keyws.insert(pair<string,Keywords>("function", FUN));
    Keyws.insert(pair<string,Keywords>("procedure", PROC));
    Keyws.insert(pair<string,Keywords>("true", TRUEB));
    Keyws.insert(pair<string,Keywords>("false", TRUEB));

}

Keywords Scanner::getnextsym() {
  char ch;
  char* LAbuffer;
  Keywords retval;
  
  do{ ch=myfile.get();
        if (ch =='\n'){
            Writer::getInstance()->incrementLine();
        }
  }
  while (is_blank(ch));

  if(ch == '{'){
      do{ 
          ch=myfile.get();
          if(ch == EOF){
              return ENDFILE;
          }
      }while (ch != '}');
      ch = myfile.get();
      while (is_blank(ch)){ 
        ch=myfile.get();
        if (ch =='\n'){
            Writer::getInstance()->incrementLine();
        }
      }
  }
  
  err_line = cur_line;
  err_col  = cur_col;
  
  cout << "Curr char:" << ch << endl;
  
  switch (ch) {
      case EOF: return ENDFILE;
      case '+': return PLUS;
      case '-': return MINUS;
      case '*': return MUL;
      case '/': return DIV;
      case '=': return EQ;
      case '(': return LST_INIT;
      case ')': return LST_END;
      case ',': return EXPR_SEP;
      case ';': return ISTR_SEP;
      case '.': return PRG_END;
      case ':':
                if(myfile.get()=='='){
                        retval=ASSIGN;
                        
                }
                else{
                        
                        retval=TYPE_SEP;
                        myfile.unget();
                }
               
                return retval;
      case '<':{
          int nextch = myfile.get();
          switch(nextch){
              case '>': retval=NE;break;
              case '=': retval=LE;break;
              default:retval=GT; 
                      myfile.unget();
                      break;
          }
          return retval;}
      case '>':{
          if(myfile.get()=='='){
              retval=GE;
          }
          else{
              retval=GT;
              myfile.unget();
          }
          return retval;}
    default:{
      id=scan_word(ch);
      if (isdigit(ch)) {
          scan_int(id,num);
          ExtendedSymbolTable::getInstance()->setLastNum(num);
          num = 0;
          return NUM;
      }
      if (isalpha(ch)) {
          Keywords entry;
          
          if(Keyws.find(id) != Keyws.end()){
              entry = Keyws.find(id)->second;
              return entry;
          }
          else{
              ExtendedSymbolTable::getInstance()->setLastId(id);
              return ID;
          }
      }
      Writer::getInstance()->errorReport(UNDEFTOK,id);
      return ERROR;
    }
  }
      return ERROR;
}

/*void Scanner::error_recover(ifstream mystream){
    char ch;
    do char ch=mystream.get();
    while (!is_end(ch));
}*/
int Scanner::init_scan(const char fn[]) {
  cur_line = 1;
  cur_col = 0;
  ExtendedSymbolTable::getInstance();
  myfile.open (fn, ifstream::in);
  if (!myfile) {
		cerr << "Input file missing. Terminating the application";
		exit(-1);
	}
  init_keywords();
  //static
  //Ops.insert(Abstract_ops.GT,">");
  /*keywords = create_htab(11);
  enter_htab(keywords, "begin", beginsym);
  enter_htab(keywords, "call", callsym);
  enter_htab(keywords, "const", constsym);
  enter_htab(keywords, "do", dosym);
  enter_htab(keywords, "end", endsym);
  enter_htab(keywords, "if", ifsym);
  enter_htab(keywords, "odd", oddsym);
  enter_htab(keywords, "procedure", procsym);
  enter_htab(keywords, "then", thensym);
  enter_htab(keywords, "var", varsym);
  enter_htab(keywords, "while", whilesym);
  return 1;*/
}

bool Scanner::scan_int(string in,int& out){
    boost::regex const string_matcher("[0-9]*");
    if(!boost::regex_match(in, string_matcher))
        return false;
    if(in=="0") return 0;
    out=atoi(in.c_str());
    return true;
}

bool Scanner::scan_id(std::string in){
    boost::regex const string_matcher("[a-zA-Z]([a-zA-Z]|[0-9]|_)*");
    if(!boost::regex_match(in, string_matcher))
        return false;
    else return true;
}


char Scanner::scan_alpha(int in){
    if((in>='A' && in<='z') || in=='_')
        return (char)in;
    else return (char)NULL;
}

bool Scanner::remove_comments(){
    Keywords k;
    do{
        k=getnextsym();
        if(k==COMM_INIT)
            return false;
    }while(k!=COMM_END);
    return true;
}
bool Scanner::is_blank(char ch){
    return ch==' ' || ch=='\t' || ch=='\n';
}

bool Scanner::is_end(char ch){
    return ch=='.' || ch==';';
}

string Scanner::scan_word(char ch){
    int id_len = 0;
    char* id=(char*)malloc(2*sizeof(char));
    //id[0]=ch;
    do {
        id[id_len++] = ch;
        ch=myfile.get();
    } while (ch != EOF && !is_blank(ch) && (( ch >='0' && ch<'9') || (ch>='A' && ch<'Z') || (ch>=97 && ch<123)));
    id[id_len] = '\0'; 
    myfile.unget();
    return id;
}

bool Scanner::scan(){
    while(getnextsym()!=PRG_END);
}

Scanner::Scanner(const char filename[]): cur_line(1),cur_col(0),err_line(1),err_col(0),num() {
    int a=init_scan(filename);
}


Scanner::~Scanner() {
    
}

